

import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;

import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.MouseInputAdapter;


/* 
 * This displays an image.  When the user drags within
 * the image, this program displays a rectangle and a string
 * indicating the bounds of the rectangle.
 */
public class SelectionDemo {
    JLabel label;
    static JButton save;
    static String map = "Images/input.png";
    JSpinner spinner;
    Node node = new Node();
    Route route = new Route();
    JLabel routeLabel;
    boolean solveBool = false;
    SelectionArea area;
    static int num = 0;
    private void buildUI(Container container, ImageIcon image) {
        container.setLayout(new BoxLayout(container,
                                          BoxLayout.PAGE_AXIS));
        //useless statement
        Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();                                  
        
        
        spinner = new JSpinner(new SpinnerNumberModel(1, 1, 10, 1));
        label = new JLabel("Drag within the map.");
        save = new JButton("Solve");
        routeLabel = new JLabel("");
        
         area = new SelectionArea(image, this);
        JLabel truckLabel = new JLabel("Number of trucks:");
        JLabel titleLabel = new JLabel("Map: UPLB");
        JButton resetButton = new JButton("Reset");
        JScrollPane scrollPane = new JScrollPane(area,
                JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        scrollPane.setPreferredSize(new Dimension(Math.min(image.getIconWidth(),dim.width),Math.min( image.getIconHeight(), dim.height)));
        
        save.addActionListener(new ActionListener() {
       	 
            public void actionPerformed(ActionEvent e)
            {	VRP solver = new VRP();
                //Execute when button is pressed
           solver.solve( node.generateNodeArray(node), Integer.parseInt((spinner.getValue().toString())), route);
           solveBool = true;
           area.repaint();
            }
        }); 
        
        resetButton.addActionListener(new ActionListener() {
          	 
            public void actionPerformed(ActionEvent e)
            {	
            	for (int i = 0; i < num +1;i++){
            		area.currentRect[i].setBounds(0,0,0,0);
            		area.rectToDraw[i].setBounds(0,0,0,0);
            		
            		
            	}
            	for(int i= 0; i< route.list.length; i++){
            		route.list[i].clear();
            	}
            	 node.xList.clear();
            	 node.yList.clear();
            	
            	num = 0;
            	area.repaint();
            	
            	
            }
        }); 
       
        
        
        label.setLabelFor(area);
        
        container.setLayout(null);
        
        container.setSize(dim.width, dim.height);
      
        
        titleLabel.setBounds(0, 0, 400, 50);
        scrollPane.setBounds(0, 50, 900, 600);
        label.setBounds(0, 630, 300, 100);
        truckLabel.setBounds(950,40,200,100);
        spinner.setBounds(1000, 100, 50, 30);
        save.setBounds(1000, 150, 80, 30);
        resetButton.setBounds(1000, 200, 80, 30);
        routeLabel.setBounds(1000,200,400,400);
        
        
        
        container.add(titleLabel);
        container.add(scrollPane);
        container.add(truckLabel);
        container.add(label);
        container.add(spinner);
        container.add(save);
        container.add(resetButton);
        container.add(routeLabel);
        
        
        
    }

    public void updateLabel(Rectangle rect) {
        int width = rect.width;
        int height = rect.height;

        //Make the coordinates look OK if a dimension is 0.
        if (width == 0) {
            width = 1;
        }
        if (height == 0) {
            height = 1;
        }

        label.setText("Node #"+ num + "goes from ("
                      + rect.x + ", " + rect.y + ") to ("
                      + (rect.x + width - 1) + ", "
                      + (rect.y + height - 1) + ").");
    }

    /** Returns an ImageIcon, or null if the path was invalid. */
    protected static ImageIcon createImageIcon(String path) {
        java.net.URL imgURL = SelectionDemo.class.getResource(path);
        if (imgURL != null) {
            return new ImageIcon(imgURL);
        } else {
            System.err.println("Couldn't find file: " + path);
            return null;
        }
    }

    
    private static void createAndShowGUI() {
        //Create and set up the window.
        JFrame frame = new JFrame("Prototype1");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Set up the content pane.
        SelectionDemo controller = new SelectionDemo();
        controller.buildUI(frame.getContentPane(),
                           createImageIcon(map));

        //Display the window.
        
      
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI(); 
            }
        });
    }
    
    @SuppressWarnings("serial")
	private class SelectionArea extends JLabel{
        Rectangle [] currentRect =new Rectangle [100];
        Rectangle [] rectToDraw = new Rectangle [100];
        Rectangle previousRectDrawn = new Rectangle();
      
        SelectionDemo controller;
       
        public SelectionArea(ImageIcon image, SelectionDemo controller) {
            super(image); //This component displays an image.
            this.controller = controller;
            setOpaque(true);
            setMinimumSize(new Dimension(10,10)); //don't hog space
    
            for(int i = 0; i <currentRect.length; i++){
            	currentRect[i] = new Rectangle(0, 0, 0, 0);
            	rectToDraw[i] = new Rectangle(0, 0, 0, 0);
            }
   
            MyListener myListener = new MyListener();
            addMouseListener(myListener);
            addMouseMotionListener(myListener);
        }
    
        private class MyListener extends MouseInputAdapter {
            public void mousePressed(MouseEvent e) {
                int x = e.getX();
                int y = e.getY();
                currentRect[num].setBounds(x, y, 0, 0);
               
                updateDrawableRect(getWidth(), getHeight());
                repaint();
            }
    
            public void mouseDragged(MouseEvent e) {
                updateSize(e);
            }
    
            public void mouseReleased(MouseEvent e) {
            	createNewRect(e);
            }
    
          
             
            void updateSize(MouseEvent e) {
                int x = e.getX();
                int y = e.getY();
                currentRect[num].setSize(x - currentRect[num].x,
                                    y - currentRect[num].y);
                updateDrawableRect(getWidth(), getHeight());
                Rectangle totalRepaint = rectToDraw[num].union(previousRectDrawn);
                repaint(totalRepaint.x, totalRepaint.y,
                        totalRepaint.width, totalRepaint.height);
            }
            
            void createNewRect(MouseEvent e) {
               if(num < currentRect.length){
            	   node.xList.add( currentRect[num].getCenterX());
            	   node.yList.add( currentRect[num].getCenterY());
            	   num++;
            	  }
            
            }
            
           
        }
    
        protected void paintComponent(Graphics g) {
            super.paintComponent(g); //paints the background and image
            Graphics2D g2 = (Graphics2D) g;
            //If currentRect exists, paint a box on top.
            if (currentRect[num] != null) {
                //Draw a rectangle on top of the image.
                 //Colour of line varies
                                           //depending on image colours
                
            	g.setColor(new Color(255, 0, 0, 56));
                	
                g.fillRect(rectToDraw[0].x, rectToDraw[0].y, 
                        rectToDraw[0].width, rectToDraw[0].height);
                
                
                g.setXORMode(Color.white);
                for(int i=1;i<num+1;i++){
                	
                	if(i!=num){
                	g.setColor(new Color(20,0, 130, 50));
                	 g.fillRect(rectToDraw[i].x, rectToDraw[i].y, 
                             rectToDraw[i].width, rectToDraw[i].height);
             
                	}else{
                		g.setColor(new Color(0, 0, 0));
                		g.drawRect(rectToDraw[i].x, rectToDraw[i].y, 
                                rectToDraw[i].width -1, rectToDraw[i].height -1);
                	}
                	   controller.updateLabel(rectToDraw[i]);
                }
               
              
            }
            
            if(solveBool){
            	
            	for(int i = 0; i< route.list.length; i++){
            		
            		g2.setColor(new Color((int)(Math.random()*255),(int)(Math.random()*255),(int)(Math.random()*255)));
   
            		for(int j=0; j< route.list[i].size()-1;j++){
            			
            			g2.draw(new Line2D.Double( currentRect[route.list[i].get(j)].getCenterX(),  currentRect[route.list[i].get(j)].getCenterY()
            					, currentRect[route.list[i].get(j+1)].getCenterX() , currentRect[route.list[i].get(j+1)].getCenterY() ));
            			g2.draw(new Line2D.Double( currentRect[route.list[i].get(j)].getCenterX()+1,  currentRect[route.list[i].get(j)].getCenterY()+1
            					, currentRect[route.list[i].get(j+1)].getCenterX()+1 , currentRect[route.list[i].get(j+1)].getCenterY()+1 ));
            			g2.draw(new Line2D.Double( currentRect[route.list[i].get(j)].getCenterX()+2,  currentRect[route.list[i].get(j)].getCenterY()+2
            					, currentRect[route.list[i].get(j+1)].getCenterX()+2 , currentRect[route.list[i].get(j+1)].getCenterY()+2 ));
            				
            		}
            	}
            	
            }
        }
    
        private void updateDrawableRect(int compWidth, int compHeight) {
            int x = currentRect[num].x;
            int y = currentRect[num].y;
            int width = currentRect[num].width;
            int height = currentRect[num].height;
    
            //Make the width and height positive, if necessary.
            if (width < 0) {
                width = 0 - width;
                x = x - width + 1; 
                if (x < 0) {
                    width += x; 
                    x = 0;
                }
            }
            if (height < 0) {
                height = 0 - height;
                y = y - height + 1; 
                if (y < 0) {
                    height += y; 
                    y = 0;
                }
            }
    
            //The rectangle shouldn't extend past the drawing area.
            if ((x + width) > compWidth) {
                width = compWidth - x;
            }
            if ((y + height) > compHeight) {
                height = compHeight - y;
            }
            	width = Math.min(width, 100);
            
           
            	height = Math.min(height, 100);
             
           
            if (rectToDraw[num] != null) {
                previousRectDrawn.setBounds(
                            rectToDraw[num].x, rectToDraw[num].y, 
                            rectToDraw[num].width, rectToDraw[num].height);
                rectToDraw[num].setBounds(x, y, width, height);
            }
        }
       
		
    }


}
